#import "InstanceManager.h"
#import "GlyphView.h"
#import <appkit/Application.h>
#import <appkit/Text.h>
#import <appkit/Panel.h>
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/NXSplitView.h>
#import <appkit/Matrix.h>
#import <appkit/NXImage.h>
#import <appkit/NXCursor.h>
#import <objc/objc-class.h>
#import <objc/List.h>
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <stdlib.h>
#import <strings.h>
#import <libc.h>
#import "NuString.h"
#import "MenuManager.h"
#import "NuWraps.h"
#import <appkit/nextstd.h>

extern char bigBuf[] ;
static char lastPath[256] ; // last path in the browser
NXRect boundsRect ; // used to remember visible boundary
  // of glyphView during resize operations
union _alltypes // data types we can display in insVarBrowser
{ NXRect NXRectType ;
  NXPoint NXPointType ;
  NXSize NXSizeType ;
  double doubleType ;
  float floatType ;
  int intType ;
  unsigned unsignedIntType ;
  id idType ;
  short shortType ;
  unsigned short unsignedShortType ;
  char * stringType ;
  char charType ;
} *allTypes ;

// cursor used when resizing
id sizerCursor = nil ;

// knobs for resizing, using code from Draw and then
// optimized
static int KNOB_WIDTH = 5.0;
static int KNOB_HEIGHT = 5.0;
static NXRect blackRectList[8] ;
static NXRect dkgrayRectList[8];


static void drawKnobs(const NXRect *rect)
{  NXRect knob ;
   NXRect *rectList ;
   NXCoord dx, dy;
   BOOL oddx, oddy;
   int i = 0  ;
   knob = *rect;
   rectList = blackRectList ; 
   while(1) // do blackRects first, then dkgrayRects
   { dx = knob.size.width / 2.0;
     dy = knob.size.height / 2.0;
     oddx = (floor(dx) != dx);
     oddy = (floor(dy) != dy);
     knob.size.width = KNOB_WIDTH;
     knob.size.height = KNOB_HEIGHT;
     knob.origin.x -= ((KNOB_WIDTH - 1.0) / 2.0);
     knob.origin.y -= ((KNOB_HEIGHT - 1.0) / 2.0);
    // knobs are drawn clockwise from bottom left
   
                                                         rectList[i++] = knob ;
     knob.origin.y += dy; if(oddy) knob.origin.y -= 0.5; rectList[i++] = knob ;
     knob.origin.y += dy; if(oddy) knob.origin.y += 0.5; rectList[i++] = knob ;
     knob.origin.x += dx; if(oddx) knob.origin.x -= 0.5; rectList[i++] = knob ;  
     knob.origin.x += dx; if(oddx) knob.origin.x += 0.5; rectList[i++] = knob ;
     knob.origin.y -= dy; if(oddy) knob.origin.y -= 0.5; rectList[i++] = knob ;
     knob.origin.y -= dy; if(oddy) knob.origin.y += 0.5; rectList[i++] = knob ;
     knob.origin.x -= dx; if(oddx) knob.origin.x += 0.5; rectList[i++] = knob ;
     if(rectList == dkgrayRectList) // then we're done
       break ;
     // set up for the dkgray iteration
     rectList = dkgrayRectList ;
     knob = *rect ; i = 0 ;
     knob.origin.x -= 1.0; knob.origin.y += 1.0;
  }
  PSsetgray(NX_DKGRAY);
  PSsetlinewidth(0.0) ;
  NXFrameRectWithWidth(rect,0.0) ;
  PSsetgray(NX_BLACK);
  NXRectFillList(blackRectList, 8);
  PSsetgray(NX_DKGRAY);
  NXRectFillList(dkgrayRectList, 8);
}

static void drawKnobsAux(llx,lly, urx, ury)
float llx,lly,urx,ury ;
{ // convert to an NXRect, then call drawKnobs
  NXRect aRect = {{llx,lly},{urx-llx,ury-lly}} ;
  return drawKnobs(&aRect) ;
}

@implementation InstanceManager:WorkspaceManager
{ // ivars for the widgets
  id originX, originY, originLink ;
  id scaleWidth, scaleHeight, scaleLink ;
  id resizeType ;
  // ivars for the browser and text
  id splitView ;
  id insVarBrowser ;
  id classList, insVarList ;
  // hang on to targetGlyph and GlyphView id's
  Glyph *targetGlyph ;
  GlyphView *glyphView ;
  // resizing rectangle
  float llx, lly, urx, ury ;
  float llxm, llym, urxm, urym ;
  // ivar for knobbies
  BOOL sizerRunning ; // true iff the knobbies are on
  NXRect targetFrame ; // frame of targetGlyph in glyphView coords
  NXRect trackRect ; // tracking rectangle for knobbies in base coords
}



+ cursor ;
{ // returns the cursor to use during
  // resize operations
  static id cursor = nil ;
  if(!cursor)
  { id anImage ;
    NXSize aSize = {16.0,16.0} ;
    NXPoint hotSpot = {2.0,2.0} ;
    anImage = [[NXImage alloc] initSize: &aSize] ;
    [anImage lockFocus] ;
    PSsendstring(
   "0 setalpha "
   "1 setgray "
   "0 0 16 16 rectfill "
   "1 setalpha "
   "1 setgray "
     "0 setgray "
     "0 11 5 5 rectfill "
     "stroke ") ;              
    PScvx() ;
    PSexec() ;
    [anImage unlockFocus] ;
    cursor = [[NXCursor alloc] initFromImage: anImage] ;
    [cursor setHotSpot: &hotSpot] ;
  }
  return cursor ;
}

- accept: sender ;
{ // change my state according to the vals
  // in the text fields
  NXPoint aPnt ;
  double  mx, my ;
  targetGlyph = [Nu targetGlyph] ;
  if(!targetGlyph->flags.isRoot) // can't move rootGlyph
  { aPnt.x = [[originX cell] floatValue] ;
    aPnt.y = [[originY cell] floatValue] ;
    [[glyphView rootGlyph] moveGlyph: targetGlyph
      toPoint: &aPnt ofGlyph: [targetGlyph ancestor]] ;
  }
  aPnt.x = [[scaleWidth cell] floatValue] ;
  aPnt.y = [[scaleHeight cell] floatValue] ;
  mx = aPnt.x / targetGlyph->scale.width ;
  my = aPnt.y / targetGlyph->scale.height ;
  [[glyphView rootGlyph] resizeTargetBy: mx :my
     pile: [resizeType selectedCol]] ;
  return self ;
}

- ancestor: sender ;
{ return
    [self changeTargetTo: [targetGlyph ancestor]] ;
}



- (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
{ if(column == 0)
  { // then this is the class column
    return [classList count] ;
  }
  else // column == 1
  { struct objc_ivar_list *aList ;
    struct objc_class *aClass  ;
    int i,knt ;
    Ivar theVar ;
    id theText ;
    [insVarList freeObjects] ;
    aClass = (struct objc_class *)  [classList objectAt:
       [[insVarBrowser matrixInColumn: 0] selectedRow]] ;
    aList = aClass->ivars ;
    if(!aList) // no list at all when 0 ivars
      return 0 ; 
    knt = aList->ivar_count ;
    for(i = 0 ; i < knt ; i++)
    { theVar = &(aList->ivar_list[i]) ;
      [insVarList addObject:
        theText = [NuString new: theVar->ivar_type]] ;
      [theText catString: " "] ;
      [theText catString: theVar->ivar_name] ;
    }
    return knt ;
  }
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
{ if(column == 0)
  { [cell setStringValue: [[classList objectAt: row] name]] ;
    [cell setLeaf: NO] ;
  }
  else // column == 1
  { [cell setLeaf: YES] ;
    [cell setStringValue: [[insVarList objectAt: row] cString]] ;
  }
  return self ;
}

- changeTargetTo: (Glyph *) aGlyph ;
{ if(!aGlyph->flags.isTerminator)
  { [aGlyph becomeTarget] ;
    [self instance: aGlyph] ;
  }
  return self ;
}

- clone: sender ;
{ // clone the target glyph, than plant it in the current
  // target after moving it halfway across the and halfway
  // up the current target.  Then make the clone the current
  // target.
  Glyph *aClone ;
  aClone = [targetGlyph clone] ;
  aClone->frame.origin.x = targetGlyph->frame.origin.x +
	targetGlyph->frame.size.width / 2.0 ;
  aClone->frame.origin.y = targetGlyph->frame.origin.y +
  	targetGlyph->frame.size.height / 2.0 ;
  [aClone moveOriginTo: &aClone->frame.origin ofGlyph: targetGlyph->ancestor] ;
  [aClone becomeTarget] ;
  return self ;
}

- delete: sender ;
{ return [targetGlyph die] ;
}

- dOX: sender ;
{ id aCell = [originX cell] ;
  [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  if([originLink state])
    [originY setFloatValue: [originY floatValue] - 1.0] ;
  [self accept: self] ;
  return self ;
}

- dOY: sender ;
{ id aCell = [originY cell] ;
  [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  if([originLink state])
    [originX setFloatValue: [originX floatValue] - 1.0] ;
  [self accept: self] ;
  return self ;
}


- dSW: sender ;
{ id aCell = [scaleWidth cell] ;
  [aCell setFloatValue: [aCell floatValue] - 1.0] ;
  if([scaleLink state])
   [[scaleHeight cell] setFloatValue: [aCell floatValue]] ;
  [self accept: self] ;
  return self ;
}

- dSH: sender ;
{ id aCell = [scaleHeight cell] ;
  [aCell  setFloatValue: [aCell floatValue] - 1.0] ;
  if([scaleLink state])
   [[scaleWidth cell] setFloatValue: [aCell floatValue]] ;
  [self accept: self] ;
  return self ;
}


- instance: aGlyph ;
{ // setup the insVarBrowser to browse this
  // Glyph
  struct objc_class *aClass, *glyphSuperClass ;
  if(!aGlyph)
  { return nil ;
  }
  targetGlyph = aGlyph ;
  glyphView = [Nu glyphView] ;
  [self setTitle: [targetGlyph name]] ;
  // update the scale and origin
  [[scaleWidth  cell] setFloatValue: targetGlyph->scale.width] ;
  [[scaleHeight cell] setFloatValue: targetGlyph->scale.height] ;
  [self setOrigin] ;

  [classList empty] ; // don't wanna free these guys!
  [insVarList freeObjects] ;
  // make class list for this class
  aClass = (struct objc_class *) [targetGlyph class] ;
  glyphSuperClass = 
    (struct objc_class *) [objc_getClass("Glyph") superClass]  ;
  while(aClass != glyphSuperClass)
  { // walk the inheritance chain
    [classList addObject: (id) aClass] ;
    aClass = aClass->super_class ;
  }
  [insVarBrowser loadColumnZero] ;
  [insVarBrowser setPath: lastPath] ;
  [self showValue: self] ;
  return self ;
}

- iOX: sender ;
{ id aCell = [originX cell] ;
  [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  if([originLink state])
    [originY setFloatValue: [originY floatValue] + 1.0] ;
  [self accept: self] ;
  return self ;
}

- iOY: sender ;
{ id aCell = [originY cell] ;
  [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  if([originLink state])
    [originX setFloatValue: [originX floatValue] + 1.0] ;
  [self accept: self] ;
  return self ;
}

- init ;
{ // set the browser to two columns only
  [insVarBrowser setAutoresizeSubviews: YES] ;
  [insVarBrowser setMinColumnWidth: 1.0] ;
  [insVarBrowser setMaxVisibleColumns: 2] ;
  // assemble the pieces we get from the nib
  [insVarBrowser useScrollButtons: YES] ;
  [splitView addSubview: [insVarBrowser removeFromSuperview]] ;
  [splitView addSubview: [[[textView superview] superview]
      removeFromSuperview]] ;
  // make sure we are not monofont
  [textView setMonoFont: NO] ; 
  isRTF =  NO ;
  [self setMiniwindowIcon: "cmIcon.tiff"] ;
  // become the textView's delegate so we'll get a textDidGetKeys:isEmpty:
  // whenever the text is edited
  [textView setDelegate: self] ;
  // make lastPath empty
  lastPath[0] = '\0' ;
  // create Storage for class names and
  // Ivar names
  classList = [List new] ;
  insVarList = [List new] ;
  return self ;
}


- is: sender ;
{ return
    [self changeTargetTo: [targetGlyph is]] ;
}


- iSW: sender ;
{ id aCell = [scaleWidth cell] ;
  [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  if([scaleLink state])
   [[scaleHeight cell] setFloatValue: [aCell floatValue]] ;
  [self accept: self] ;
  return self ;
}

- iSH: sender ;
{ id aCell = [scaleHeight cell] ;
  [aCell setFloatValue: [aCell floatValue] + 1.0] ;
  if([scaleLink state])
   [[scaleWidth cell] setFloatValue: [aCell floatValue]] ;
  [self accept: self] ;
  return self ;
}

NXPoint eventOrigin ; // remember where event began
BOOL mouseDragged  ; // set to YES if a mouseDragged is received
// mouse messages are relayed from
// glyphView during resizing operations

- mouseDown: (NXEvent *) anEvent ;
{ int i ;
  mouseDragged = NO ;
  // make sure glyphView and instance are up-to-date
  glyphView = [Nu glyphView] ;
  [self instance: [Nu targetGlyph]] ;
  // set llx,lly,urx,ury tp target's frame
  targetFrame = targetGlyph->frame ;
  [[targetGlyph ancestor] convertToRootGlyph: &targetFrame.origin] ;
  llx = targetFrame.origin.x ;
  lly = targetFrame.origin.y ;
  urx = llx + targetFrame.size.width ;
  ury = lly + targetFrame.size.height ;
  // draw the knobs
  [glyphView lockFocus] ; // unlocked in mouseUp:
  PSnewinstance() ;
  PSsetinstance(YES) ;
  drawKnobsAux(llx,lly,urx,ury) ;
  PSsetinstance(NO) ;
  // remember the event's origin
  eventOrigin = anEvent->location ;
  [glyphView convertPoint: &eventOrigin fromView: nil] ;
  // find if cursor is in a knobbie
  for(i = 0 ; i < 8 ; i++) 
  { if(NXPointInRect(
       (const NXPoint *) &eventOrigin,(const NXRect *) &(blackRectList[i])))
        break ;
  }
  // (if i == 8, then not in knobbies)
  // figure out the multipliers used to compute the next
  // position of the knobbies
  llxm = llym = urxm = urym = 0.0 ;
  if(i <= 2)
    llxm = 1.0 ;
  else if((4 <= i) &&  (i <= 6))
    urxm = 1.0 ;
  if((i == 0) || (i == 7) || (i == 6))
    llym = 1.0 ; 
  else if((i == 2) || (i == 3) || (i == 4))
    urym = 1.0 ;
  return self ;
}


- mouseDragged: (NXEvent *) anEvent ;
{ float dx, dy, temp ;
  float prevllx = llx, prevlly = lly,
        prevurx = urx, prevury = ury ;
  mouseDragged = YES ;
  [glyphView convertPoint: &anEvent->location fromView: nil] ;
  dx = anEvent->location.x - eventOrigin.x ;
  dy = anEvent->location.y - eventOrigin.y ;
  eventOrigin = anEvent->location ;
  if(llxm + llym + urxm + urym == 2.0) // moving 2 coords?
  { // If so, must maintain the glyph's aspect ratio.
    // Are we pulling from upper left or lower right?
    BOOL upperLeftOrLowerRight = (llxm && urym) || (urxm && llym) ;
    // compute current aspect ratio (we must maintain this)
    float aspect = (urx - llx) / (ury - lly) ;
    // Find which coord moved the most, then recompute the other
    // coord using this coord andthe aspect ratio
    // compute dy from thes new dx and the aspect ratio
    if(abs(dx) > abs(dy)) // more x motion
    {  dy = dx / aspect ; 
       if(upperLeftOrLowerRight)
         dy *= -1.0 ;
    }
    else
    { dx = dy * aspect ;
       if(upperLeftOrLowerRight)
         dx *= -1.0 ;
    }
  }
  // apply dx and dy to the resizing rectangle 
  temp = dx * llxm ;
  if((llx + temp) >= urx) // don't allow!
    temp = 0.0 ;
  else
    llx += temp ;
  [[originX cell] setFloatValue: [originX floatValue] + temp] ;
  temp = dy * llym ;
  if((lly + temp) >= ury) // don't allow!
    temp = 0.0 ;
  else
    lly += temp  ;
  [[originY cell] setFloatValue: [originY floatValue] + temp] ;
  urx += dx * urxm ;
  if(urx <= llx) // don't allow this to happen!
    urx = llx + 1.0 ;
  [[scaleWidth cell] setFloatValue: [scaleWidth floatValue] *
     (urx - llx) / (prevurx - prevllx)] ;
  ury += dy * urym ;
  if(ury <= lly) // don't allow this!
    ury = lly + 1.0 ;
  [[scaleHeight cell] setFloatValue: [scaleHeight floatValue] *
     (ury - lly) / (prevury - prevlly)] ;
  PSnewinstance() ;
  PSsetinstance(YES) ;
  drawKnobsAux(llx,lly,urx,ury) ;
  PSsetinstance(NO) ;
  return self ;
}

- mouseUp: (NXEvent *) anEvent ;
{ if(mouseDragged) // if the target was resized...
    [self accept: self] ;
  // need to redraw the knobs here, otherwise
  // they end up half obscured
  PSnewinstance() ;
  PSsetinstance(YES) ;
  drawKnobsAux(llx,lly,urx,ury) ;
  PSsetinstance(NO) ;
  [glyphView unlockFocus] ;
  return self ;
}

- precursor: sender ;
{ return
    [self changeTargetTo: [targetGlyph  precursor]] ;
}


- setOrigin ;
{ // set the origin values 
  [[originX cell] setFloatValue: targetGlyph->frame.origin.x] ;
  [[originY cell] setFloatValue: targetGlyph->frame.origin.y] ;
  return self ;
}


- setValue: sender ;
{ // set the value of the selected ivar. The
  // code here is symmetrical with the code
  // for showValue: 
  NXStream *aStream ;
  struct objc_ivar_list *aList ;
  struct objc_class *aClass  ;
  Ivar theVar ;
  int i,j, textLen ;
  if(![self isDocEdited])
  // only set the value if the user actually typed something
  // in the textView
    return self ;
  i = [[insVarBrowser matrixInColumn: 1] selectedRow] ;
  j = [[insVarBrowser matrixInColumn: 0] selectedRow] ;
  if(i < 0 || j < 0) 
     return nil ;
  aClass = (struct objc_class *)  [classList objectAt: j] ;
  aList = aClass->ivars ;
  theVar = &(aList->ivar_list[i]) ;
  allTypes =   &(((char *)targetGlyph)[theVar->ivar_offset]) ;
  aStream = [textView stream] ;
  // make sure we are null terminated
  switch(theVar->ivar_type[0])
  { case 'd': // double
      NXScanf(aStream,"%lf\n",&allTypes->doubleType) ;
      break ;
    case 'f': // float
      NXScanf(aStream,"%f\n",&allTypes->floatType) ;
      break ;
    case 'i': // integer
      NXScanf(aStream,"%d\n",&allTypes->intType) ;
      break ;
    case 'I': // unsigned integer
      NXScanf(aStream,"%u\n",&allTypes->unsignedIntType) ;
      break ;
    case 's': // short
      NXScanf(aStream,"%hd\n",&allTypes->shortType) ;
      break ;
    case 'S': // unsigned short
      NXScanf(aStream,"%hu\n",&allTypes->unsignedShortType) ;
      break ;
    case '{': // a struct, but what kind of struct?
      if(!strncmp(theVar->ivar_type,"{_NXPoint}",10)) 
        NXScanf(aStream,"%f@%f",
	 &allTypes->NXPointType.x, &allTypes->NXPointType.y) ;
      else if(!strncmp(theVar->ivar_type,"{_NXSize}",9)) 
        NXScanf(aStream,"%f@%f",
	 &allTypes->NXSizeType.width, &allTypes->NXSizeType.height) ;
      else if(!strncmp(theVar->ivar_type,"{_NXRect}",9))
         NXScanf(aStream,"%f@%f,%f@%f\n",
           &allTypes->NXRectType.origin.x,&allTypes->NXRectType.origin.y,
	  &allTypes->NXRectType.size.width, &allTypes->NXRectType.size.width) ;
      else
      {  sprintf(bigBuf,"Cannot set value for type %s",
           theVar->ivar_type) ;
	[textView setText: bigBuf] ;
	NXPing() ;
         usleep(1000000) ;
      }
      break ;
      case 'c': // character type
      case 'C': // unsigned char ... enter in octal
	{ int tmp ;
           NXScanf(aStream,"\\%o",&tmp) ;
	  allTypes->charType = tmp & 0x00ff ;
	}
	break ;
      case '*': // string type
         // free old string, allocate new one
         free(allTypes->stringType) ;
         textLen = [textView textLength] + 1 ;
         allTypes->stringType = (char *) malloc(textLen) ;
	[textView getSubstring: allTypes->stringType
             start: 0 length: textLen] ;
	break ;	
       case '@': // id type
         { // look for "Location: <path string> 
	  id aGlyph ;
	  char path[256] ;
	  NXScanf(aStream,"Location:%s\n",path) ;
	  aGlyph = [targetGlyph glyphAtPath: path] ;
	  if(!aGlyph)
	  { sprintf(bigBuf,"Error. No glyph at path: %s",path) ;
	    [textView setText: bigBuf] ;
	    NXPing() ;
             usleep(1000000) ;
           }
 	  else
	    allTypes->idType = aGlyph ;
	}
         break ;
      default:
	sprintf(bigBuf,"Cannot set value for type %s",
           theVar->ivar_type) ;
	[textView setText: bigBuf] ;
	NXPing() ;
         usleep(1000000) ;
	break ;
  }
  return [self showValue: self] ;
}

- showValue: sender ;
{ // show the value of the selected ivar
  struct objc_ivar_list *aList ;
  struct objc_class *aClass  ;
  Ivar theVar ;
  int i,j ;
  i = [[insVarBrowser matrixInColumn: 1] selectedRow] ;
  j = [[insVarBrowser matrixInColumn: 0] selectedRow] ;
  if(i < 0 || j < 0)
  { [textView setText: ""] ;
    return nil ;
  }
  // set default path to the last path, if possible
  [insVarBrowser getPath: lastPath toColumn: 2] ;
  aClass = (struct objc_class *)  [classList objectAt: j] ;
  aList = aClass->ivars ;
  theVar = &(aList->ivar_list[i]) ;
  allTypes =   &(((char *)targetGlyph)[theVar->ivar_offset]) ;
  bigBuf[0] = '\0' ;
  switch(theVar->ivar_type[0])
  { case 'd': // double
      sprintf(bigBuf,"%lf\n",allTypes->doubleType) ;
      break ;
    case 'f': // float
      sprintf(bigBuf,"%f\n",allTypes->floatType) ;
      break ;
    case 'i': // integer
      sprintf(bigBuf,"%d\n",allTypes->intType) ;
      break ;
    case 'I': // unsigned integer
      sprintf(bigBuf,"%u\n",allTypes->unsignedIntType) ;
      break ;
    case 's': // short
      sprintf(bigBuf,"%hd\n",allTypes->shortType) ;
      break ;
    case 'S': // unsigned short
      sprintf(bigBuf,"%hu\n",allTypes->unsignedShortType) ;
      break ;
    case '{': // a struct, but what kind of struct?
      if(!strncmp(theVar->ivar_type,"{_NXPoint}",10)) 
        sprintf(bigBuf,"%f@%f",
	 allTypes->NXPointType.x, allTypes->NXPointType.y) ;
      else if(!strncmp(theVar->ivar_type,"{_NXSize}",9)) 
        sprintf(bigBuf,"%f@%f",
	 allTypes->NXSizeType.width, (allTypes->NXSizeType).height) ;
      else if(!strncmp(theVar->ivar_type,"{_NXRect}",9))
         sprintf(bigBuf,"%f@%f,%f@%f\n",
           allTypes->NXRectType.origin.x,allTypes->NXRectType.origin.y,
	  allTypes->NXRectType.size.width, allTypes->NXRectType.size.width) ;
      else
	sprintf(bigBuf,"Cannot display value for type %s",
           theVar->ivar_type) ;
      break ;
      case 'c': // character type
	sprintf(bigBuf,"\\%o\n0x%x\n%d\n'%c'\n",allTypes->charType & 0x00ff,
           allTypes->charType & 0x00ff,
           allTypes->charType,allTypes->charType) ;
	break ;
      case 'C': // unsigned char 
	sprintf(bigBuf,"\\%o\n0x%x\n%u\n'%c'\n",allTypes->charType & 0x00ff,
           allTypes->charType & 0x00ff,
           allTypes->charType,allTypes->charType) ;
	break ;
      case '*': // string type
	sprintf(bigBuf,"%s\n",allTypes->stringType) ;
	break ;	
       case '@': // id type
	sprintf(bigBuf,"Location: 0x%x\nInstance name: %s\nClassName:%s\n",
          allTypes->idType,
	 [allTypes->idType name],
          [[allTypes->idType class] name]) ;
      break ;
      default:
	sprintf(bigBuf,"Cannot display value for type %s",
           theVar->ivar_type) ;
        break ;
  }
  [textView setText: bigBuf] ;
  NXPing() ;
  [self setDocEdited: NO] ;
  return self ;
}

- startSizer: sender ;
{ // start up for resizing the target glyph
  glyphView = [Nu glyphView] ; // get current glyphView and target glyph
  [self instance: [Nu targetGlyph]] ;
  targetFrame = targetGlyph->frame ;
  [[targetGlyph ancestor] convertToRootGlyph: &targetFrame.origin] ;
  // the resizing rectangle is described using 4 floats...
  llx = targetFrame.origin.x ;
  lly = targetFrame.origin.y ;
  urx = llx + targetFrame.size.width ;
  ury = lly + targetFrame.size.height ;
  // draw it
  [glyphView lockFocus] ;
  PSnewinstance() ;
  PSsetinstance(YES) ;
  drawKnobsAux(llx,lly,urx,ury) ; 
  PSsetinstance(NO) ;
  [glyphView unlockFocus] ;
  return self ;
}

- stopSizer: sender ;
{ PSnewinstance() ; // clear instance drawing
  return self ;
}

- targetGlyph ;
{ return targetGlyph ;
}

- textDidGetKeys:(id) theText isEmpty: (BOOL) flag ;
{ if(![self isDocEdited])
   [self setDocEdited: YES] ;
}

- then: sender ;
{ return
    [self changeTargetTo: [targetGlyph  then]] ;
}


@end
